package com.yjzx.util.service.aop.fileUpload;

import com.yjzx.util.common.execption.UtilException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * @author yjzx
 * @date 2024/06/04
 * @description 文件上传校验
 */
@Aspect
@Component
@Slf4j
public class FileUploadAspect {
    private final Map<Method, AtomicInteger> locks = new ConcurrentHashMap<>();

    /*
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-aop</artifactId>
      </dependency>
    */
    @Pointcut("execution(public * com..controller..*.*(..))")
    public void execute() {
    }

    @Around("execute()&&@annotation(fileUpload)")
    public Object doAround(ProceedingJoinPoint joinPoint, FileUpload fileUpload) throws Throwable {
        if (fileUpload != null) {
            Method method = getMethod(joinPoint);
            if (fileUpload.isLock()) {
                try {
                    lock(method, fileUpload);
                    return around(joinPoint, fileUpload);
                } finally {
                    unlock(method);
                }
            } else {
                return around(joinPoint, fileUpload);
            }
        } else {
            return joinPoint.proceed();
        }

    }

    private Object around(ProceedingJoinPoint joinPoint, FileUpload fileUpload) throws Throwable {
        for (Object arg : joinPoint.getArgs()) {
            if (arg instanceof MultipartFile) {
                MultipartFile file = (MultipartFile) arg;
                //10M
                int fileMaxSize = fileUpload.fileSize();
                if (file.getSize() > fileMaxSize) {
                    throw new UtilException("文件太大,超过" + (fileMaxSize / 0x100000D) + "M");
                }
                boolean flag = true;
                if (fileUpload.isCheckFileType()) {
                    flag = false;
                    String[] types = fileUpload.fileType();
                    String contentType = file.getContentType();
                    for (String type : types) {
                        flag = type != null && type.equals(contentType);
                        if (flag) {
                            break;
                        }
                    }
                }
                boolean flag1 = true;
                if (fileUpload.isCheckFileSuffix()) {
                    flag1 = false;
                    String[] suffixes = fileUpload.fileSuffix();
                    String name = file.getOriginalFilename();
                    for (String suffix : suffixes) {
                        flag1 = name != null && suffix != null && name.toUpperCase().endsWith(suffix.toUpperCase());
                        if (flag1) {
                            break;
                        }
                    }
                }
                if (flag && flag1) {
                    long start = System.currentTimeMillis();
                    Object proceed = joinPoint.proceed();
                    long end = System.currentTimeMillis();
                    long m = end - start;
                    log.info("导入成功,耗时:" + (m / 1000) + "s" + (m % 1000) + "ms");
                    return proceed;
                }
                throw new UtilException(fileUpload.typeErrorMsg());
            }
        }
        throw new UtilException("请传入附件");
    }

    public void lock(Method method, FileUpload fileUpload) {
        AtomicInteger n = locks.get(method);
        if (n == null) {
            locks.put(method, new AtomicInteger(1));
        } else if (n.get() < fileUpload.numberOfFiles()) {
            n.getAndIncrement();
        } else {
            throw new UtilException("存在导入中的数据或导入中的数量过多，请稍等导入");
        }
    }

    public void unlock(Method method) {
        AtomicInteger atomicInteger = locks.get(method);
        if (atomicInteger != null && atomicInteger.getAndDecrement() <= 0) {
            locks.remove(method);
        }
    }

    private Method getMethod(ProceedingJoinPoint joinPoint) throws NoSuchMethodException {
        return joinPoint.getTarget().getClass().getMethod(joinPoint.getSignature().getName(), ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes());
    }
}